/*
 * app_dispatcher.hpp
 *
 *  Created on: Feb 14, 2011
 *      Author: daniel
 */

#ifndef APP_DISPATCHER_HPP_
#define APP_DISPATCHER_HPP_

#include <doeplus/webapp/defines.hpp>
#include <doeplus/webapp/server.hpp>
#include <doeplus/webapp/app.hpp>
#include <doeplus/webapp/dispatcher.hpp>
#include <doeplus/webapp/controller.hpp>
#include <map>
#include <list>
#include <string>
#include <utility>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/threadpool.hpp>
//#include <boost/thread.hpp>

namespace doeplus{ namespace webapp{

class app_dispatcher{

private:
	doeplus::webapp::server &_server;
	doeplus::webapp::dispatcher_base::ptr _dispatcher;
//	boost::thread_group threads;

	typedef std::pair<doeplus::webapp::app*,doeplus::webapp::dispatcher_base::ptr> app_dispatcher_pair;
	typedef std::map<std::string,app_dispatcher_pair> app_map;

	app_map app_paths;
	boost::threadpool::pool threadpool;

public:
	bool connection_handler(doeplus::webapp::connection::ptr connection){
		// Lets split the path and find out what app to use
		std::list<std::string> paths;
		boost::split(paths,connection->request_uri,boost::is_any_of("/"));

		// Find out what app and controllers to use.
		paths.pop_front();	// Remove the first element since the path always start with a "/"
		if(paths.size()>0){
			std::string app_path	= paths.front();
			paths.pop_front();

			app_map::iterator it = this->app_paths.find(app_path);
			if(it!=this->app_paths.end()){
				// APP is found
				//std::list<doeplus::webapp::dispatcher::ptr> paths;
				// Create rootcontroller
				controller::ptr root_ctrl(it->second.second->create());

				std::list<controller::ptr> controllers;
				controllers.push_back(root_ctrl);

				// Dispatch down
				return it->second.second->dispatch(controllers,paths,connection);
//					if(!it->second.second->dispatch(controllers,paths,connection)){
					// Dispatch worked
//				}else{
//					connection->response_code	= 404;
//					static std::string noControllerFoundError("No controller or action found");
//					connection->send_response(noControllerFoundError,true);
//					throw doeplus::webapp::http_exception(404,noControllerFoundError.c_str());
//					return false;
//				}
			}else{
				return false;
//				connection->response_code	= 404;
//				static std::string noWebappFoundError("No webapp found");
//				connection->send_response(noWebappFoundError,true);
//				throw doeplus::webapp::http_exception(404,noWebappFoundError.c_str());
			}

		}
		return false;
	}


public:

	app_dispatcher(doeplus::webapp::server &server) :
        _server(server),
        threadpool(5)   // Start  with 5 thread in the threadpool
         {
		server.connection_callback()	= boost::bind(&app_dispatcher::connection_handler,this,_1);
	}

	~app_dispatcher(){

	}

	template<typename C,typename APP> void add_app(APP &app,const char* subpath){
		doeplus::webapp::dispatcher<C> *holder	= new doeplus::webapp::dispatcher<C>();
		doeplus::webapp::dispatcher_base::ptr dispatcher_ptr(holder);
		app_dispatcher_pair app_pair(&app,dispatcher_ptr);
		this->app_paths[subpath]	= app_pair;

		// Read the subcontrollers from the webapp
		C::dispatch_setup(holder);
	}

};

} }


#endif /* APP_DISPATCHER_HPP_ */
